#include "exporterutility.h"
#include "exporterutilitydesc.h"
#include "exportobject.h"
#include "resource.h"
#include <fstream>
#include <vector>
#include <queue>

using namespace std;

#define dimof(x) (sizeof(x)/sizeof(x[0]))

map<string,ExportMaterial*> ExporterUtility::SceneMaterials;

//
// Construction
//
ExporterUtility::ExporterUtility ()
{
}


//
// Destruction
//
ExporterUtility::~ExporterUtility ()
{
}


//
// From UtilityObj
//
void ExporterUtility::BeginEditParams (Interface *ip, IUtil *iu)
{
    hRollup = ip->AddRollupPage( ExporterUtilityDesc::TheInstance()->HInstance(), MAKEINTRESOURCE(IDD_DIALOG1), DlgProc, "Generic Exporter" );

    CheckDlgButton( hRollup, IDC_ALL, BST_CHECKED );
    CheckDlgButton( hRollup, IDC_32BIT, BST_CHECKED );
    CheckDlgButton( hRollup, IDC_OPTIMIZE, BST_CHECKED );

    if ( GetCOREInterface()->GetSelNodeCount() != 1 ) UpdObjectPanel( NULL );
    else UpdObjectPanel( ip->GetSelNode(0) );

}

void  ExporterUtility::EndEditParams (Interface *ip, IUtil *iu)
{
    ip->DeleteRollupPage( hRollup );
    DestroyWindow( hRollup );
}

void  ExporterUtility::DeleteThis ()
{
    // No deletion needed, since only instance is static.
}

void ExporterUtility::SelectionSetChanged(Interface *ip,IUtil *iu)
{

    if ( ip->GetSelNodeCount() != 1 ) UpdObjectPanel( NULL );
    else UpdObjectPanel( GetCOREInterface()->GetSelNode(0) );
}

void ExporterUtility::UpdObjectPanel( INode *SelNode )
{
    if ( !SelNode )
    {
        EnableWindow( GetDlgItem( hRollup, IDC_VERTEXANIM ), false );
        EnableWindow( GetDlgItem( hRollup, IDC_UV1 ), false );
        EnableWindow( GetDlgItem( hRollup, IDC_UV2 ), false );
        EnableWindow( GetDlgItem( hRollup, IDC_UV3 ), false );
        EnableWindow( GetDlgItem( hRollup, IDC_UV4 ), false );
        SendDlgItemMessage( hRollup, IDC_UV1, BM_SETSTATE, (WPARAM)FALSE, 0 );
        SendDlgItemMessage( hRollup, IDC_UV2, BM_SETSTATE, (WPARAM)FALSE, 0 );
        SendDlgItemMessage( hRollup, IDC_UV3, BM_SETSTATE, (WPARAM)FALSE, 0 );
        SendDlgItemMessage( hRollup, IDC_UV4, BM_SETSTATE, (WPARAM)FALSE, 0 );
        CheckDlgButton( hRollup, IDC_VERTEXANIM, BST_UNCHECKED );
    } else {
        EnableWindow( GetDlgItem( hRollup, IDC_VERTEXANIM ), true );
        EnableWindow( GetDlgItem( hRollup, IDC_UV1 ), true );
        EnableWindow( GetDlgItem( hRollup, IDC_UV2 ), true );
        EnableWindow( GetDlgItem( hRollup, IDC_UV3 ), true );
        EnableWindow( GetDlgItem( hRollup, IDC_UV4 ), true );

    }
}

INT_PTR CALLBACK ExporterUtility::DlgProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch ( message )
    {
    case WM_COMMAND:
    {
        UINT notifycode = HIWORD(wParam);
        UINT id = LOWORD(wParam);
        switch ( notifycode )
        {
        case BN_CLICKED:
        {
            switch ( id )
            {
            // Export /////////////////////////////////////////////////////////////////////////////////
            case IDC_EXPORT:
            {
                ExporterUtilityDesc::ClassInstance()->Export();
                break;
            }
            case IDC_EXPORTAS:
            {
                OPENFILENAME ofn;
                char fname[MAX_PATH];
                char szFile[MAX_PATH];
                *szFile = 0;
                strcpy(szFile,"*.xml");
                ZeroMemory( &ofn, sizeof(ofn) );
                ofn.lStructSize = sizeof(ofn);
                ofn.hwndOwner = NULL;
                ofn.lpstrFile = szFile;
                ofn.nMaxFile = MAX_PATH;
                ofn.lpstrFilter = "XML file\0*.xml\0";
                ofn.nFilterIndex = 1;
                ofn.lpstrFileTitle = NULL;
                ofn.nMaxFileTitle = 0;
                ofn.lpstrInitialDir = NULL;
                //	ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
                if ( GetSaveFileName( &ofn ) )
                    ExporterUtilityDesc::ClassInstance()->Export( ofn.lpstrFile );
                break;
            }
            case IDC_VIEW:
            {
                STARTUPINFO StartupInfo = { sizeof(STARTUPINFO) };
                PROCESS_INFORMATION	ProcessInformation;
                /*string filename = string(GetCOREInterface()->GetCurFilePath()).RelPath(ExporterUtilityDesc::ClassInstance()->m_szMaxModelPath).RemExt()+CString(".wld");
                CRegistry R;
                R.Open();
                string szExeFile;
                R.GetValue( CString("ProjectPath"), szExeFile );
                szExeFile += CString("game.exe");
                BOOL ret = CreateProcess( szExeFile, filename.m_szString, NULL, NULL, TRUE, NULL, NULL, "C:\\western\\", &StartupInfo, &ProcessInformation );
                R.Close();*/
                break;
            }
            // Object properties //////////////////////////////////////////////////////////////////////////////
            }
        }
        }
    }
    }

    return DefWindowProc( hWnd, message, wParam, lParam );
}

DWORD WINAPI progressfn(LPVOID arg)
{
    return(0);
}

void ExporterUtility::Export()
{   
    if ( !IsDlgButtonChecked( hRollup, IDC_SEPARATE ) )
    {
		Export( "c:\\test.xml" );
    } else {
    	ExportSeparate();
    }
}

void ExporterUtility::ExportSeparate()
{   /*
    CLIST<ExportObject> objs;

    INode *pRootNode = GetCOREInterface ()->GetRootNode ();
    int NumChildren = pRootNode->NumberOfChildren();

    Interface *ip = GetCOREInterface();
    ip->ProgressStart("Exporting...", TRUE, progressfn, 0);

    Interval iv = ip->GetAnimRange();
    TimeValue TicksPerFrame = GetTicksPerFrame();

    int firstnode = 0;
    if ( IsDlgButtonChecked( hRollup, IDC_SELECTED ) )
    {
    	// find first selected node
    	for ( int i = 0; i < NumChildren; i++ )
    	{
    		INode *N = pRootNode->GetChildNode(i);
    		if ( pRootNode->GetChildNode(i)->Selected() )
    		{
    			ExportObject *O = ExportObject::BuildFromINode( pRootNode->GetChildNode(i) );
    			if ( O ) objs.Add( O );
    			firstnode = i;
    			break;
    		} else {
    			DPrint("Skipping node %s.\n", N->GetName() );
    		}
    	}
    } else {
    	ExportObject* O = ExportObject::BuildFromINode( pRootNode->GetChildNode(0) );
    	if ( O ) objs.Add( O );
    }

    for ( int i = firstnode+1; i < NumChildren; i++ )
    {
    	if ( pRootNode->GetChildNode(i)->Selected() || !IsDlgButtonChecked( hRollup, IDC_SELECTED ))
    	{
    		ExportObject *O = ExportObject::BuildFromINode( pRootNode->GetChildNode(i) );
    		if ( O ) objs.Add( O );
    	}
    }

    ip->ProgressUpdate( 0, FALSE, "Saving..." );


    while ( objs.Count )
    {
    	ExportObject *obj=objs.GetFirst();
    	cFile F;
    	F.Create( m_szProjectPath+m_szMeshPath+CString(GetCOREInterface()->GetCurFilePath()).GetPath().RelPath( m_szMaxModelPath )+CString(obj->GetName())+CString(".wld") );
    	DPrint( "%s\n", obj->GetName().m_szString );
    	obj->Save( F );
    	obj->PostSave( F );
    	objs.DeleteFirst();
    	F.Close();
    }

    ip->ProgressEnd();
    */
}

void ExporterUtility::BeginXml( ostream &os )
{
	os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl;
	os << "<ModelData xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"http://www.example.org/NewXMLSchema\">" << endl;
}

void ExporterUtility::EndXml( ostream &os )
{
	os << "</ModelData>" << endl;
}

void ExporterUtility::GetAllChildren(INode *n, queue<INode*> &q)
{
	for ( int i = 0; i < n->NumberOfChildren(); i++ )
    {
		q.push(n->GetChildNode(i));
		GetAllChildren(n->GetChildNode(i), q);
	}
}

void ExporterUtility::Export( const string &fname )
{
    INode *pRootNode = GetCOREInterface ()->GetRootNode ();
    int NumChildren = pRootNode->NumberOfChildren();

	if (!NumChildren) return;

    Interface *ip = GetCOREInterface();
    ip->ProgressStart("Exporting...", TRUE, progressfn, 0);

	ip->ProgressUpdate( 0, FALSE, "Saving..." );

	ofstream of(fname);

	BeginXml(of);

	queue<INode*> objs;


	SceneMaterials.clear();

    Interval iv = ip->GetAnimRange();
    TimeValue TicksPerFrame = GetTicksPerFrame();

	GetAllChildren(pRootNode,objs);

	while ( objs.size() )
    {
		if (IsDlgButtonChecked( hRollup, IDC_SELECTED ) && !objs.front()->Selected())
		{
			objs.pop();
			continue;
		}
		ExportObject *obj=ExportObject::BuildFromINode(objs.front());
		objs.pop();
		if (obj)
		{
    		obj->BeginWrite( of );
			obj->EndWrite( of );
    		delete obj;
		}
    }


	WriteMaterials(of);

    ip->ProgressEnd();

	EndXml(of);

	of.close();
}

void ExporterUtility::WriteMaterials(ostream &stream)
{
	stream << "<Materials>" << endl;
	for (map<string,ExportMaterial*>::iterator it = SceneMaterials.begin(); it != SceneMaterials.end(); ++it)
	{
		it->second->Write(stream);
	}
	stream << "</Materials>" << endl;
}

bool FindBone( int& steps, INode* start, INode* end )
{
    if ( start == end )
        return true;
    else
    {
        //OutputDebugString( start->GetName() );
        steps++;
        for ( int i = 0; i < start->NumberOfChildren(); i++ )
        {
            if ( FindBone( steps, start->GetChildNode( i ), end ) )
                return true;
        }
    }

    return false;
}
